Mart Layer
The mart layer transforms canonical models into specific use cases, such as dashboards, reports, or business unit requirements. These models are designed to serve particular business needs while maintaining consistency with the canonical layer.
Example Folder Structure
models
└── marts
├── finance
│ ├── revenue_dashboard/
│ │ ├── daily_revenue.sql
│ │ └── customer_ltv.sql
│ └── reporting/
│ ├── monthly_p_and_l.sql
│ └── cash_flow.sql
├── marketing
│ ├── campaign_performance/
│ │ ├── campaign_roi.sql
│ │ └── channel_metrics.sql
│ └── customer_analytics/
│ ├── cohort_analysis.sql
│ └── customer_segments.sql
└── sales
└── sales_reporting/
├── sales_targets.sql
└── team_performance.sql
Structure Best Practices
- ✅ Business Unit Grouping ~ Organize by department or function
- ✅ Use Case Subfolders ~ Group related models by their purpose
- ✅ Clear Naming ~ Names should reflect the business purpose
Example Model
-- models/marts/finance/revenue_dashboard/daily_revenue.sql
WITH customer_orders AS (
SELECT * FROM {{ ref('customers') }} -- from canonical layer
),
order_data AS (
SELECT * FROM {{ ref('orders') }} -- from canonical layer
),
final AS (
SELECT
date_trunc('day', order_date) as date,
customer_segment,
count(distinct customer_id) as unique_customers,
sum(order_value) as daily_revenue,
sum(order_value) / count(distinct customer_id) as average_order_value
FROM order_data o
JOIN customer_orders c
ON o.customer_id = c.customer_id
GROUP BY 1, 2
)
SELECT * FROM final
Materialization
Marts should typically be materialized as tables:
# dbt_project.yml
models:
your_project:
marts:
+materialized: table
Why Tables?
- Optimized for end-user query performance
- Refreshed on a schedule matching business needs
- Complex calculations already processed
- Ready for BI tool consumption